home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 25 / CU Amiga Magazine's Super CD-ROM 25 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-08].iso / CUCD / Programming / QuakeTools / src / libqbuild / qbsp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-11  |  14.7 KB  |  636 lines

  1. #define    LIBQBUILD_CORE
  2. #include "../include/libqbuild.h"
  3.  
  4. //
  5. // command line flags
  6. //
  7. int subdivide_size = 240;
  8.  
  9. struct brushset *brushset;
  10.  
  11. int valid;
  12.  
  13. char bspfilename[NAMELEN_PATH];
  14. char pointfilename[NAMELEN_PATH];
  15. char portfilename[NAMELEN_PATH];
  16. char hullfilename[NAMELEN_PATH];
  17.  
  18. char *argv0;                                       // changed after fork();
  19.  
  20. bool worldmodel;
  21.  
  22. int hullnum;
  23.  
  24. int c_activefaces, c_peakfaces;
  25. int c_activeleafs, c_peakleafs;
  26. int c_activesurfaces, c_peaksurfaces;
  27. int c_activeportals, c_peakportals;
  28.  
  29. //===========================================================================
  30.  
  31. void PrintMemory(void)
  32. {
  33.   int i, j;
  34.   int a, b;
  35.  
  36.   mprintf(" faces   : %5i, %7i (%5i, %7i)\n", c_activefaces, j = c_activefaces * sizeof(struct visfacet),
  37.                                               c_peakfaces, i = c_peakfaces * sizeof(struct visfacet));
  38.   a = j;
  39.   b = i;
  40.   mprintf(" surfaces: %5i, %7i (%5i, %7i)\n", c_activesurfaces, j = c_activesurfaces * sizeof(struct surface),
  41.                                               c_peaksurfaces, i = c_peaksurfaces * sizeof(struct surface));
  42.   a += j;
  43.   b += i;
  44.   mprintf(" windings: %5i, %7i (%5i, %7i)\n", c_activewindings, j = c_activewindings * sizeof(struct winding),
  45.                                               c_peakwindings, i = c_peakwindings * sizeof(struct winding));
  46.   a += j;
  47.   b += i;
  48.   mprintf(" portals : %5i, %7i (%5i, %7i)\n", c_activeportals, j = c_activeportals * sizeof(struct portal),
  49.                                               c_peakportals, i = c_peakportals * sizeof(struct portal));
  50.   a += j;
  51.   b += i;
  52.   mprintf("-------------------------------------------\n");
  53.   mprintf("                  %7i (       %7i)\n\n", a, b);
  54. }
  55.  
  56. /*
  57.  * ===========
  58.  * AllocLeaf
  59.  * ===========
  60.  */
  61. struct visleaf *AllocLeaf(register int prtals)
  62. {
  63.   struct visleaf *l;
  64.  
  65.   c_activeleafs++;
  66.   if (c_activeleafs > c_peakleafs)
  67.     c_peakleafs = c_activeleafs;
  68.  
  69.   if(!(l = (struct visleaf *)tmalloc(sizeof(struct visleaf))))
  70.     Error("AllocLeaf: failed to allocate leaf!\n");
  71. #ifdef DYNAMIC_EDGES
  72.   /* at least one point available */
  73.   if(prtals < 0)
  74.     prtals = 0;
  75.   if(!(l->portals = (struct visportal **)tmalloc((prtals) * sizeof(struct visportal *))))
  76.     Error("AllocLeaf: failed to allocate portals!\n");
  77. #endif
  78.   return l;
  79. }
  80.  
  81.  
  82. void RecalcLeaf(register struct visleaf *l) {
  83. #ifdef DYNAMIC_EDGES
  84.   /* at least one point available */
  85.   int prtals = l->numportals;
  86.   if(prtals < 0)
  87.     prtals = 0;
  88.   if(!(l->portals = (struct visportal **)trealloc(l->portals , (prtals) * sizeof(struct visportal *))))
  89.     Error("RecalcFace: failed to allocate face!\n");
  90. #endif
  91. }
  92.  
  93. void FreeLeaf(register struct visleaf *l)
  94. {
  95.   c_activeleafs--;
  96. #ifdef DYNAMIC_EDGES
  97.   tfree(l->portals);
  98. #endif
  99.   tfree(l);
  100. }
  101.  
  102. /*
  103.  * ===========
  104.  * AllocFace
  105.  * ===========
  106.  */
  107. struct visfacet *AllocFace(register int points)
  108. {
  109.   struct visfacet *f;
  110.  
  111.   c_activefaces++;
  112.   if (c_activefaces > c_peakfaces)
  113.     c_peakfaces = c_activefaces;
  114.  
  115.   if(!(f = (struct visfacet *)tmalloc(sizeof(struct visfacet))))
  116.     Error("AllocFace: failed to allocate face!\n");
  117.   //memset(f, 0, sizeof(struct visfacet));
  118.   f->planenum = -1;
  119. #ifdef DYNAMIC_EDGES
  120.   /* at least one point available */
  121.   if(points < 0)
  122.     points = 0;
  123.   if(!(f->pts   = (vec3_t *)tmalloc((points) * sizeof(vec3_t))))
  124.     Error("AllocFace: failed to allocate points!\n");
  125.   if(!(f->edges = (int *)   tmalloc((points) * sizeof(int)   )))
  126.     Error("AllocFace: failed to allocate edges!\n");
  127. #endif
  128.   return f;
  129. }
  130.  
  131. void CopyFace(register struct visfacet *out, register struct visfacet *in) {
  132. #ifdef DYNAMIC_EDGES
  133.   /* at least one point available */
  134.   short int points = in->numpoints;
  135.   vec3_t *pts;
  136.   int *edges;
  137.   
  138.   if(points < 0)
  139.     points = 0;
  140.   tfree(out->pts);
  141.   tfree(out->edges);
  142.   if(!(pts   = (vec3_t *)tmalloc((points) * sizeof(vec3_t))))
  143.     Error("CopyFace: failed to allocate face!\n");
  144.   if(!(edges = (int *)   tmalloc((points) * sizeof(int)   )))
  145.     Error("CopyFace: failed to allocate face!\n");
  146.   if(points) {
  147.     memcpy(pts  , in->pts  , points * sizeof(vec3_t));
  148.     memcpy(edges, in->edges, points * sizeof(int)   );
  149.   }
  150. #endif
  151.   memcpy(out, in, sizeof(struct visfacet));
  152. #ifdef DYNAMIC_EDGES
  153.   out->pts   = pts;
  154.   out->edges = edges;
  155. #endif
  156. }
  157.  
  158. void RecalcFace(register struct visfacet *f) {
  159. #ifdef DYNAMIC_EDGES
  160.   /* at least one point available */
  161.   short int points = f->numpoints;
  162.   if(points < 0)
  163.     points = 0;
  164.   if(!(f->pts   = (vec3_t *)trealloc(f->pts  , (points) * sizeof(vec3_t))))
  165.     Error("RecalcFace: failed to allocate face!\n");
  166.   if(!(f->edges = (int *)   trealloc(f->edges, (points) * sizeof(int)   )))
  167.     Error("RecalcFace: failed to allocate face!\n");
  168. #endif
  169. }
  170.  
  171. void FreeFace(register struct visfacet *f)
  172. {
  173.   c_activefaces--;
  174. #ifdef DYNAMIC_EDGES
  175.   tfree(f->pts);
  176.   tfree(f->edges);
  177. #endif
  178.   tfree(f);
  179. }
  180.  
  181. /*
  182.  * ===========
  183.  * AllocSurface
  184.  * ===========
  185.  */
  186. struct surface *AllocSurface(void)
  187. {
  188.   struct surface *s;
  189.  
  190.   if(!(s = (struct surface *)tmalloc(sizeof(struct surface))))
  191.     Error("AllocSurface: failed to allocate surface!\n");
  192.   //memset(s, 0, sizeof(struct surface));
  193.  
  194.   c_activesurfaces++;
  195.   if (c_activesurfaces > c_peaksurfaces)
  196.     c_peaksurfaces = c_activesurfaces;
  197.  
  198.   return s;
  199. }
  200.  
  201. void FreeSurface(register struct surface *s)
  202. {
  203.   c_activesurfaces--;
  204.   tfree(s);
  205. }
  206.  
  207. /*
  208.  * ===========
  209.  * AllocPortal
  210.  * ===========
  211.  */
  212. struct portal *AllocPortal(void)
  213. {
  214.   struct portal *p;
  215.  
  216.   c_activeportals++;
  217.   if (c_activeportals > c_peakportals)
  218.     c_peakportals = c_activeportals;
  219.  
  220.   if(!(p = (struct portal *)tmalloc(sizeof(struct portal))))
  221.     Error("AllocPortal: failed to allocate portal!\n");
  222.   //memset(p, 0, sizeof(struct portal));
  223.  
  224.   return p;
  225. }
  226.  
  227. void FreePortal(register struct portal *p)
  228. {
  229.   c_activeportals--;
  230.   tfree(p);
  231. }
  232.  
  233. /*
  234.  * ===========
  235.  * AllocNode
  236.  * ===========
  237.  */
  238. struct node *AllocNode(void)
  239. {
  240.   struct node *n;
  241.  
  242.   if(!(n = (struct node *)tmalloc(sizeof(struct node))))
  243.     Error("AllocNode: failed to allocate node!\n");
  244.   //memset(n, 0, sizeof(struct node));
  245.  
  246.   return n;
  247. }
  248.  
  249. /*
  250.  * ===========
  251.  * AllocBrush
  252.  * ===========
  253.  */
  254. struct brush *AllocBrush(void)
  255. {
  256.   struct brush *b;
  257.  
  258.   if(!(b = (struct brush *)tmalloc(sizeof(struct brush))))
  259.     Error("AllocNode: failed to allocate node!\n");
  260.   //memset(b, 0, sizeof(struct brush));
  261.  
  262.   return b;
  263. }
  264.  
  265. //===========================================================================
  266.  
  267. /*
  268.  * ===============
  269.  * ProcessEntity
  270.  * ===============
  271.  */
  272. void ProcessEntity(__memBase, register int entnum)
  273. {
  274.   struct entity *ent;
  275.   char mod[80];
  276.   struct surface *surfs;
  277.   struct node *nodes;
  278.   struct brushset *bs;
  279.  
  280.   ent = &bspMem->mapentities[entnum];
  281.   if (!ent->brushes)
  282.     return;                                       // non-bmodel entity
  283.  
  284.   if (entnum > 0) {
  285.     worldmodel = FALSE;
  286.     if (entnum == 1)
  287.       mprintf("----- Internal Entities ---\n");
  288.     sprintf(mod, "*%i", bspMem->nummodels);
  289.  
  290.     if (hullnum == 0)
  291.       mprintf("    - MODEL: %s\n", mod);
  292.     SetKeyValue(ent, "model", mod);
  293.   }
  294.   else
  295.     worldmodel = TRUE;
  296.  
  297. //
  298.   // take the brush_ts and clip off all overlapping and contained faces,
  299.   // leaving a perfect skin of the model with no hidden faces
  300.   //
  301.   bs = Brush_LoadEntity(bspMem, ent, hullnum);
  302.  
  303.   if (!bs->brushes) {
  304.     PrintEntity(ent);
  305.     Error("Entity with no valid brushes");
  306.   }
  307.  
  308.   brushset = bs;
  309.   surfs = CSGFaces(bspMem, bs);
  310.  
  311.   if (hullnum != 0) {
  312.     nodes = SolidBSP(bspMem, surfs, TRUE);
  313.     if (entnum == 0 && !(bspMem->bspOptions & QBSP_NOFILL))               // assume non-world bmodels are simple
  314.      {
  315.       PortalizeWorld(bspMem, nodes);
  316.       if (FillOutside(bspMem, nodes, pointfilename)) {
  317.     surfs = GatherNodeFaces(bspMem, nodes);
  318.     nodes = SolidBSP(bspMem, surfs, FALSE);                       // make a really good tree
  319.       }
  320.       FreeAllPortals(nodes);
  321.     }
  322.     WriteNodePlanes(bspMem, nodes);
  323.     WriteClipNodes(bspMem, nodes);
  324.     BumpModel(bspMem, hullnum);
  325.   }
  326.   else {
  327.     //
  328.     // SolidBSP generates a node tree
  329.     //
  330.     // if not the world, make a good tree first
  331.     // the world is just going to make a bad tree
  332.     // because the outside filling will force a regeneration later
  333.     nodes = SolidBSP(bspMem, surfs, entnum == 0);
  334.  
  335.     //
  336.     // build all the portals in the bsp tree
  337.     // some portals are solid polygons, and some are paths to other leafs
  338.     //
  339.     if (entnum == 0 && !(bspMem->bspOptions & QBSP_NOFILL))               // assume non-world bmodels are simple
  340.      {
  341.       PortalizeWorld(bspMem, nodes);
  342.  
  343.       if (FillOutside(bspMem, nodes, pointfilename)) {
  344.     FreeAllPortals(nodes);
  345.  
  346.     // get the remaining faces together into surfaces again
  347.     surfs = GatherNodeFaces(bspMem, nodes);
  348.  
  349.     // merge polygons
  350.     MergeAll(bspMem, surfs);
  351.  
  352.     // make a really good tree
  353.     nodes = SolidBSP(bspMem, surfs, FALSE);
  354.  
  355.     // make the real portals for vis tracing
  356.     PortalizeWorld(bspMem, nodes);
  357.  
  358.     // save portal file for vis tracing
  359.     WritePortalfile(bspMem, nodes, portfilename);
  360.     
  361.     // fix tjunctions
  362.     if(!(bspMem->bspOptions & QBSP_NOTJUNC))
  363.       tjunc(nodes);
  364.       }
  365.       FreeAllPortals(nodes);
  366.     }
  367.  
  368.     WriteNodePlanes(bspMem, nodes);
  369.     MakeFaceEdges(bspMem, nodes);
  370.     WriteDrawNodes(bspMem, nodes);
  371.   }
  372. }
  373.  
  374. /*
  375.  * =================
  376.  * UpdateEntLump
  377.  * 
  378.  * =================
  379.  */
  380. void UpdateEntLump(__memBase)
  381. {
  382.   int m, entnum;
  383.   char mod[80];
  384.   FILE *bspFile;
  385.  
  386.   m = 1;
  387.   for (entnum = 1; entnum < bspMem->nummapentities; entnum++) {
  388.     if (!bspMem->mapentities[entnum].brushes)
  389.       continue;
  390.     sprintf(mod, "*%i", m);
  391.     SetKeyValue(&bspMem->mapentities[entnum], "model", mod);
  392.     m++;
  393.   }
  394.  
  395.   mprintf("    - updating bspMem->mapentities lump...\n");
  396.   
  397.   FreeClusters(bspMem, 0);
  398.   if((bspFile = fopen(bspfilename, READWRITE_BINARY_OLD))) {
  399.     bspMem = LoadBSP(bspFile, ALL_LUMPS);
  400.     WriteEntitiesToString(bspMem);
  401.     WriteBSP(bspFile, bspMem);
  402.     FreeClusters(bspMem, 0);
  403.     tfree(bspMem);
  404.     fclose(bspFile);
  405.   }
  406. }
  407.  
  408. //===========================================================================
  409.  
  410. /*
  411.  * =================
  412.  * WriteClipHull
  413.  * 
  414.  * Write the clipping hull out to a text file so the parent process can get it
  415.  * =================
  416.  */
  417. void WriteClipHull(__memBase)
  418. {
  419.   FILE *f;
  420.   int i;
  421.   struct dplane_t *p;
  422.   struct dclipnode_t *d;
  423.  
  424.   hullfilename[strlen(hullfilename) - 1] = '0' + hullnum;
  425.  
  426.   mprintf("----- WriteClipHull -----\n");
  427.   mprintf("    - writing %s\n", hullfilename);
  428.  
  429.   f = fopen(hullfilename, "w");
  430.   if (!f)
  431.     Error("Couldn't open %s", hullfilename);
  432.  
  433.   fprintf(f, "%i\n", bspMem->nummodels);
  434.  
  435.   for (i = 0; i < bspMem->nummodels; i++)
  436.     fprintf(f, "%i\n", bspMem->dmodels[i].headnode[hullnum]);
  437.  
  438.   fprintf(f, "\n%i\n", bspMem->numclipnodes);
  439.  
  440.   for (i = 0; i < bspMem->numclipnodes; i++) {
  441.     d = &bspMem->dclipnodes[i];
  442.     p = &bspMem->dplanes[d->planenum];
  443.     // the node number is only written out for human readability
  444.     fprintf(f, "%5i : %g %g %g %g : %5i %5i\n", i, p->normal[0], p->normal[1], p->normal[2], p->dist, d->children[0], d->children[1]);
  445.   }
  446.  
  447.   fclose(f);
  448. }
  449.  
  450. /*
  451.  * =================
  452.  * ReadClipHull
  453.  * 
  454.  * Read the files written out by the child processes
  455.  * =================
  456.  */
  457. void ReadClipHull(__memBase, register int hullnum)
  458. {
  459.   FILE *f;
  460.   int i, j, n;
  461.   int firstclipnode;
  462.   struct dplane_t p;
  463.   struct dclipnode_t *d;
  464.   int c1, c2;
  465.   float f1, f2, f3, f4;
  466.   int junk;
  467.   vec3_t norm;
  468.  
  469.   hullfilename[strlen(hullfilename) - 1] = '0' + hullnum;
  470.  
  471.   f = fopen(hullfilename, "r");
  472.   if (!f)
  473.     Error("Couldn't open %s", hullfilename);
  474.  
  475.   if (fscanf(f, "%i\n", &n) != 1)
  476.     Error("Error parsing %s", hullfilename);
  477.  
  478.   if (n != bspMem->nummodels)
  479.     Error("ReadClipHull: hull had %i models, base had %i", n, bspMem->nummodels);
  480.  
  481.   for (i = 0; i < n; i++) {
  482.     fscanf(f, "%i\n", &j);
  483.     bspMem->dmodels[i].headnode[hullnum] = bspMem->numclipnodes + j;
  484.   }
  485.  
  486.   fscanf(f, "\n%i\n", &n);
  487.   firstclipnode = bspMem->numclipnodes;
  488.  
  489.   for (i = 0; i < n; i++) {
  490.     if (bspMem->numclipnodes == bspMem->max_numclipnodes)
  491.       ExpandClusters(bspMem, LUMP_CLIPNODES);
  492.     d = &bspMem->dclipnodes[bspMem->numclipnodes];
  493.     bspMem->numclipnodes++;
  494.     if (fscanf(f, "%i : %g %g %g %g : %i %i\n", &junk, &f1, &f2, &f3, &f4, &c1, &c2) != 7)
  495.       Error("Error parsing %s", hullfilename);
  496.  
  497.     p.normal[0] = f1;
  498.     p.normal[1] = f2;
  499.     p.normal[2] = f3;
  500.     p.dist = f4;
  501.  
  502.     norm[0] = f1;
  503.     norm[1] = f2;
  504.     norm[2] = f3;                                   // vec_t precision
  505.  
  506.     p.type = PlaneTypeForNormal(norm);
  507.  
  508.     d->children[0] = c1 >= 0 ? c1 + firstclipnode : c1;
  509.     d->children[1] = c2 >= 0 ? c2 + firstclipnode : c2;
  510.     d->planenum = FindFinalPlane(bspMem, &p);
  511.   }
  512.  
  513. }
  514.  
  515. /*
  516.  * =================
  517.  * CreateSingleHull
  518.  * 
  519.  * =================
  520.  */
  521. void CreateSingleHull(__memBase)
  522. {
  523.   int entnum;
  524.  
  525. // for each entity in the map file that has geometry
  526.   for (entnum = 0; entnum < bspMem->nummapentities; entnum++)
  527.     ProcessEntity(bspMem, entnum);
  528.  
  529.   if (hullnum)
  530.     WriteClipHull(bspMem);
  531. }
  532.  
  533. /*
  534.  * =================
  535.  * CreateHulls
  536.  * 
  537.  * =================
  538.  */
  539. void CreateHulls(__memBase)
  540. {
  541. // commanded to create a single hull only
  542.   if (hullnum) {
  543.     CreateSingleHull(bspMem);
  544.     exit(0);
  545.   }
  546.  
  547. // commanded to use the allready existing hulls 1 and 2
  548.   if (bspMem->bspOptions & QBSP_USEHULLS) {
  549.     CreateSingleHull(bspMem);
  550.     return;
  551.   }
  552.  
  553. // commanded to ignore the hulls altogether
  554.   if (bspMem->bspOptions & QBSP_NOCLIP) {
  555.     CreateSingleHull(bspMem);
  556.     return;
  557.   }
  558.  
  559. // create all the hulls
  560.  
  561. // create the hulls sequentially
  562.   mprintf("    - building hulls sequentially...\n");
  563.  
  564.   hullnum = 1;
  565.   CreateSingleHull(bspMem);
  566.  
  567.   bspMem->nummodels = 0;
  568.   bspMem->numplanes = 0;
  569.   bspMem->numclipnodes = 0;
  570.   hullnum = 2;
  571.   CreateSingleHull(bspMem);
  572.  
  573.   bspMem->nummodels = 0;
  574.   bspMem->numplanes = 0;
  575.   bspMem->numclipnodes = 0;
  576.   hullnum = 0;
  577.   CreateSingleHull(bspMem);
  578. }
  579.  
  580. /*
  581.  * =================
  582.  * ProcessMem
  583.  * =================
  584.  */
  585. void ProcessMem(__memBase, register char *filebase)
  586. {
  587. // create filenames
  588.   strcpy(bspfilename, filebase);
  589.   ReplaceExt(bspfilename, "bsp");
  590.   strcpy(hullfilename, filebase);
  591.   ReplaceExt(hullfilename, "h0");
  592.   strcpy(portfilename, filebase);
  593.   ReplaceExt(portfilename, "prt");
  594.   strcpy(pointfilename, filebase);
  595.   ReplaceExt(pointfilename, "pts");
  596.  
  597.   if (bspMem->bspOptions & QBSP_ONLYENTS)
  598.     UpdateEntLump(bspMem);
  599.   else {
  600.     if (!(bspMem->bspOptions & QBSP_USEHULLS)) {
  601.       hullfilename[strlen(hullfilename) - 1] = '1';
  602.       remove(hullfilename);
  603.       hullfilename[strlen(hullfilename) - 1] = '2';
  604.       remove(hullfilename);
  605.     }
  606.     remove(portfilename);
  607.     remove(pointfilename);
  608.  
  609. // the clipping hulls will be written out to text files by forked processes
  610.     CreateHulls(bspMem);
  611.  
  612.     ReadClipHull(bspMem, 1);
  613.     ReadClipHull(bspMem, 2);
  614.  
  615.     WriteEntitiesToString(bspMem);
  616.   }
  617. }
  618.  
  619. bool qbsp(__memBase, int hullNum, int subDivide, char *filebase)
  620. {
  621.   if(hullNum) {
  622.     hullnum = hullNum;
  623.     mprintf("use hull %d\n", hullNum);
  624.   }
  625.   if(subDivide) {
  626.     subdivide_size = subDivide;
  627.     mprintf("subdivide %d\n", subDivide);
  628.   }
  629.  
  630.   ProcessMem(bspMem, filebase);
  631.   PrintMemory();
  632.  
  633.   return TRUE;
  634. }
  635.  
  636.